package com.jiashihui.schema_lgorithm.java.socket.service2;

import com.jiashihui.schema_lgorithm.java.socket.handler.common.IServiceHandler;
import com.jiashihui.schema_lgorithm.java.socket.handler.common.ServiceHandlerFactory;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.StandardCharsets;
import java.util.Iterator;

/**
 * 核心处理类
 */
public class ServerHandler extends ChannelInboundHandlerAdapter {
    private static final ChannelGroup CHANNELS = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    private static final Logger LOGGER = LoggerFactory.getLogger(ServerHandler.class);
    private static final int NUM_8 = 8;
    private static final int NUM_200 = 200;

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        try {
            Message data = (Message) msg;
            LOGGER.debug("{}:传过来的原始数据:{}", ctx.channel().remoteAddress(), data);
            // 判断主动推动客户端，客户端返回结果
            IServiceHandler handler = ServiceHandlerFactory.getHandler(data.getServiceType());
            if (null == handler) {
                LOGGER.warn("无法获取handler，无效请求！");
                return;
            }
            String result = handler.handler(data.getData());
            LOGGER.debug("{}:传回的原始数据:{}", ctx.channel().remoteAddress(), result);
            if (handler.getServiceType().isBack()) {
                sendResult(ctx, data.getServiceType(), data.getMessageId(), result);
            }
        } catch (Exception e) {
            LOGGER.error("处理服务请求出错！", e);
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }

    /**
     * 发送报文接收返回结果
     *
     * @param ctx
     */
    private void sendResult(ChannelHandlerContext ctx, int serviceType, int messageId, String data) {
        ByteBuf firstMessage = null;
        try {
            byte[] buffer = data.getBytes(StandardCharsets.UTF_8);
            // 查询长度，在头部分增加四位长度值
            int length = buffer.length;
            // 发送类
            firstMessage = Unpooled.buffer(buffer.length + NUM_8);
            firstMessage.writeInt(length + NUM_8);
            firstMessage.writeInt(serviceType);
            firstMessage.writeInt(messageId);
            // 发送
            firstMessage.writeBytes(buffer);
            ctx.writeAndFlush(Unpooled.copiedBuffer(firstMessage));
            LOGGER.debug("return message: {},{},{},{}", length + 8, serviceType, messageId, data);
        } catch (Exception e1) {
            LOGGER.error("返回结果出错！", e1);
        } finally {
            ReferenceCountUtil.release(firstMessage);
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // A closed channel will be removed from ChannelGroup automatically
        CHANNELS.add(ctx.channel());
        LOGGER.debug("connected client {}", ctx.channel().remoteAddress());
        Iterator<Channel> iterator = CHANNELS.iterator();
        while (iterator.hasNext()) {
            LOGGER.debug("目前连接着谁：{}", iterator.next().remoteAddress());
        }
        if (LOGGER.isDebugEnabled()) {
            printChannels();
        }
    }

    /**
     * 打印连接的客户端信息
     */
    private void printChannels() {
        for (Channel ch : CHANNELS) {
            LOGGER.debug("IP:{},isOpen:{},isRegistered:{},isActive:{}",
                    ch.remoteAddress(),
                    ch.isOpen(),
                    ch.isRegistered(),
                    ch.isActive());
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        CHANNELS.remove(ctx.channel());
        LOGGER.debug("Disconnected client {}", ctx.channel().remoteAddress());
        Iterator<Channel> iterator = CHANNELS.iterator();
        while (iterator.hasNext()) {
            LOGGER.debug("目前连接着谁：{}", iterator.next().remoteAddress());
        }
        LOGGER.debug("connected client num: {}", CHANNELS.size());
        if (LOGGER.isDebugEnabled()) {
            printChannels();
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        if (ctx.channel().isRegistered() || ctx.channel().isOpen() || ctx.channel().isActive() || ctx.channel().isWritable()) {
            ctx.channel().closeFuture().await(NUM_200);
        }
        ctx.close();
        LOGGER.warn(cause.getMessage());
    }

}
